#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
using namespace std;

void Usage(const std::string &proc)
{
    std::cout << "\n\rUsage: " << proc << " serverip serverport\n"
              << std::endl;
}
// ./tcpclient serverip serverport参数形式
int main(int argc,char*argv[])
{
    if(argc!=3)
    {
        Usage(argv[0]);
        exit(1);
    }
    string serverip=argv[1];
    uint16_t serverport=stoi(argv[2]);
    //利用main中传入的可变参数队服务端网络结构体进行初始化
    struct sockaddr_in server;
    memset(&server,0,sizeof(server));
    server.sin_family=AF_INET;
    server.sin_port=htons(serverport);
    inet_pton(AF_INET,serverip.c_str(),&(server.sin_addr));

    //普通版本
    // int sockfd=socket(AF_INET,SOCK_STREAM,0);
    //     if(sockfd<0)
    //     {
    //         cout<<"socket error"<<endl;
    //         return 1;
    //     }//将套接字的创建与销毁放在循环外进行长连接
    //     int n=connect(sockfd,(struct sockaddr*)&server,sizeof(server));
    //     if(n<0)//套接字不能重复连接
    //     {
    //          cout << "connect error to " << serverip << ":" << serverport 
    //          << " - " << strerror(errno) << " (errno: " << errno << ")" << endl;
    //         close(sockfd);
    //         exit(1);
    //     }
    // while(true)
    // {
    //     int cnt=5;//允许连接数
    //     //与服务器建立连接
    //     string message;
    //     cout<<"Please Enter# ";
    //     getline(cin,message);
    //     //向服务器发送信息
    //     n=write(sockfd,message.c_str(),message.size());//n变量可重复使用
    //     if(n<0)
    //     {
    //         cout<<"write error..."<<endl;
    //     }
    //     char inbuffer[4096];
    //     //接收服务器处理后的信息
    //     n=read(sockfd,inbuffer,sizeof(inbuffer));
    //     if(n>0)
    //     {
    //         inbuffer[n]=0;
    //         cout<<inbuffer<<endl;
    //     }
    //     else break;
    // }
    // close(sockfd);

    //客户端离线重连版本
    while(true)
    {
        int cnt=5;
        int isreconnect=false;
        int sockfd=0;
        sockfd=socket(AF_INET,SOCK_STREAM,0);
        if(sockfd<0)
        {
            cerr<<"socket error"<<endl;
            return 1;
        }
        do//若断连，不断尝试重连
        {
            int n=connect(sockfd,(struct sockaddr*)&server,sizeof(server));
            if(n<0)
            {
                isreconnect=true;
                cnt--;
                cerr<<"connect error..., reconnect: "<<cnt<<endl;
                sleep(2);
            }
            else{
                break;
            }
        } while(cnt&&isreconnect);
        
        if(cnt==0)
        {
            cerr<<"user offline..."<<endl;
            break;
        }
        string message;
        cout<<"Please Enter# ";
        getline(cin,message);
        //向服务器发送信息
        int n=write(sockfd,message.c_str(),message.size());//n变量可重复使用
        if(n<0)
        {
            cout<<"write error..."<<endl;
        }
        char inbuffer[4096];
        //接收服务器处理后的信息
        n=read(sockfd,inbuffer,sizeof(inbuffer));
        if(n>0)
        {
            inbuffer[n]=0;
            cout<<inbuffer<<endl;
        }
        //else break;
        close(sockfd);//一个套接字只能连接一次，重连失败后要关闭后重新申请
    }
    return 0;
}